package com.linq.cool.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linq.cool.api.domain.SysRole;
import com.linq.cool.api.domain.SysUser;
import com.linq.cool.common.constants.UserConstants;
import com.linq.cool.common.core.utils.JsonUtils;
import com.linq.cool.common.core.utils.SecurityUtils;
import com.linq.cool.common.core.utils.StringUtils;
import com.linq.cool.common.core.utils.TreeUtils;
import com.linq.cool.system.domain.SysMenu;
import com.linq.cool.system.dto.SysMenuQueryDTO;
import com.linq.cool.system.mapper.SysMenuMapper;
import com.linq.cool.system.service.SysMenuService;
import com.linq.cool.system.service.SysRoleService;
import com.linq.cool.system.vo.RouterVO;
import com.linq.cool.system.vo.TreeSelectVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: yqlin
 * @Date: 2020/12/29 19:42
 * @Description:
 * @Version: 1.0.0
 */
@Slf4j
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
    @Autowired
    private SysRoleService sysRoleService;

    @Override
    public Set<String> listMenuPermissionByUserId(Long userId) {
        List<String> menuList = baseMapper.listMenuPermissionByUserId(userId);
        Set<String> menuSet = new HashSet<>();
        for (String menu : menuList) {
            if (StringUtils.isNotEmpty(menu)) {
                menuSet.addAll(Arrays.asList(menu.trim().split(",")));
            }
        }
        return menuSet;
    }

    @Override
    public List<SysMenu> listMenuTreeByUserId(Long userId) {
        List<SysMenu> menus = null;
        if (SecurityUtils.isAdmin(userId)) {
            menus = baseMapper.listMenuTreeAll();
        } else {
            menus = baseMapper.listMenuTreeAllByUserId(userId);
        }
        log.info("listMenuTreeByUserId:{}", menus);
        return TreeUtils.toTreeList(menus, 0L, Long.class, SysMenu.class);
    }

    @Override
    public List<RouterVO> buildMenus(List<SysMenu> menus) {
        List<RouterVO> routers = new LinkedList<>();
        for (SysMenu menu : menus) {
            RouterVO router = new RouterVO();
            router.setHidden(1 == menu.getIsVisible())
                    .setName(this.getRouterName(menu))
                    .setPath(this.getRouterPath(menu))
                    .setComponent(this.getComponent(menu))
                    .setMeta(new RouterVO.MetaVO(menu.getName(), menu.getIcon(), UserConstants.StateEnum.MENU_NOT_CACHE.getCode().equals(menu.getIsCache())))
            ;
            List<SysMenu> cMenus = menu.getChildren();
            if (!CollectionUtils.isEmpty(cMenus) && UserConstants.StateEnum.MENU_TYPE_CATALOG.getCode().equals(menu.getType())) {
                router.setAlwaysShow(true)
                        .setRedirect("noRedirect")
                        .setChildren(this.buildMenus(cMenus));
            } else if (this.isMenuFrame(menu)) {
                List<RouterVO> childrenList = new ArrayList<>();
                RouterVO children = new RouterVO();
                children.setPath(menu.getPath())
                        .setComponent(menu.getComponent())
                        .setName(StringUtils.capitalize(menu.getPath()))
                        .setMeta(new RouterVO.MetaVO(menu.getName(), menu.getIcon(), UserConstants.StateEnum.MENU_NOT_CACHE.getCode().equals(menu.getIsCache())))
                ;
                childrenList.add(children);
                router.setChildren(childrenList);
            }
            routers.add(router);
        }
        return routers;
    }

    @Override
    public List<SysMenu> listByUserId(SysMenuQueryDTO dto, Long userId) {
        List<SysMenu> menuList = null;
        // 管理员显示所有菜单信息
        if (SysUser.isAdmin(userId)) {
            menuList = this.list(new LambdaQueryWrapper<SysMenu>()
                                         .like(com.baomidou.mybatisplus.core.toolkit.StringUtils.checkValNotNull(dto.getName()), SysMenu::getName, dto.getName())
                                         .eq(com.baomidou.mybatisplus.core.toolkit.StringUtils.checkValNotNull(dto.getStatus()), SysMenu::getStatus, dto.getStatus())
                                         .eq(com.baomidou.mybatisplus.core.toolkit.StringUtils.checkValNotNull(dto.getIsVisible()), SysMenu::getIsVisible, dto.getIsVisible())
                                         .orderByAsc(SysMenu::getParentId).orderByAsc(SysMenu::getSort)
            );
        } else {
            dto.getParams().put("userId", userId);
            menuList = baseMapper.listByUserId(dto);
        }
        return menuList;
    }

    @Override
    public List<TreeSelectVO> buildMenuTreeSelect(List<SysMenu> menus) {
        List<SysMenu> menuTrees = TreeUtils.toTreeList(menus, 0L, Long.class, SysMenu.class);
        log.info("menuTrees:{}", JsonUtils.printJson(menuTrees));
        return menuTrees.stream()
                .map(TreeSelectVO::new)
                .collect(Collectors.toList());
    }

    @Override
    public List<Long> listByRoleId(Long roleId) {
        SysRole role = sysRoleService.getRoleById(roleId);
        return baseMapper.listByRoleId(roleId, role.isMenuCheckStrictly());
    }

    @Override
    public boolean checkNameUnique(SysMenu menu) {
        // 判断传入的是否是空(新增或者更细) 新增的时候id menuId=-1  更新就是原来的
        Long menuId = null == menu.getId() ? -1L : menu.getId();
        SysMenu one = this.getOne(new LambdaQueryWrapper<SysMenu>()
                                          .eq(SysMenu::getName, menu.getName())
                                          .eq(SysMenu::getParentId, menu.getParentId())
        );
        // 判断id是否一致 不一致就代表 唯一 false
        return null != one && !menuId.equals(one.getId());
    }

    @Override
    public boolean hasChild(Long menuId) {
        return this.count(new LambdaQueryWrapper<SysMenu>()
                                  .eq(SysMenu::getParentId, menuId)) > 0;
    }

    @Override
    public boolean checkIsExistRole(Long menuId) {
        return baseMapper.checkIsExistRole(menuId) > 0;
    }

    /**
     * 获取组件信息
     *
     * @param menu 菜单信息
     *
     * @return 组件信息
     */
    private String getComponent(SysMenu menu) {
        String component = UserConstants.LAYOUT;
        if (StringUtils.isNotEmpty(menu.getComponent()) && !this.isMenuFrame(menu)) {
            component = menu.getComponent();
        } else if (StringUtils.isEmpty(menu.getComponent()) && this.isParentView(menu)) {
            component = UserConstants.PARENT_VIEW;
        }
        return component;
    }


    /**
     * 获取路由地址
     *
     * @param menu 菜单信息
     *
     * @return 路由地址
     */
    private String getRouterPath(SysMenu menu) {
        String routerPath = menu.getPath();
        // 非外链并且是一级目录（类型为目录）
        if (0L == menu.getParentId().intValue() && UserConstants.StateEnum.MENU_TYPE_CATALOG.getCode().equals(menu.getType())
                && UserConstants.StateEnum.MENU_FRAME_INNER.getCode().equals(menu.getIsFrame())) {
            routerPath = "/" + menu.getPath();
        }
        // 非外链并且是一级目录（类型为菜单）
        else if (this.isMenuFrame(menu)) {
            routerPath = "/";
        }
        return routerPath;
    }


    /**
     * 获取路由名称
     *
     * @param menu 菜单信息
     *
     * @return 路由名称
     */
    private String getRouterName(SysMenu menu) {
        String routerName = StringUtils.capitalize(menu.getPath());
        // 非外链并且是一级目录（类型为目录）
        if (this.isMenuFrame(menu)) {
            routerName = StringUtils.EMPTY;
        }
        return routerName;
    }


    /**
     * 是否为菜单内部跳转
     *
     * @param menu 菜单信息
     *
     * @return 结果
     */
    private boolean isMenuFrame(SysMenu menu) {
        return menu.getParentId().intValue() == 0L && UserConstants.StateEnum.MENU_TYPE_MENU.getCode().equals(menu.getType())
                && menu.getIsFrame().equals(UserConstants.StateEnum.MENU_FRAME_INNER.getCode());
    }


    /**
     * 是否为parent_view组件
     *
     * @param menu 菜单信息
     *
     * @return 结果
     */
    private boolean isParentView(SysMenu menu) {
        return menu.getParentId().intValue() != 0L && UserConstants.StateEnum.MENU_TYPE_CATALOG.getCode().equals(menu.getType());
    }
}
